]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/Tests/Unit Tests/CacheOrderTest.m
mDNSResponder-1310.40.42.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / Tests / Unit Tests / CacheOrderTest.m
1 /*
2 * Copyright (c) 2017-2019 Apple Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "unittest_common.h"
18 #import <XCTest/XCTest.h>
19
20 struct UDPSocket_struct
21 {
22 mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
23 };
24 typedef struct UDPSocket_struct UDPSocket;
25
26 // This client request was generated using the following command: "dns-sd -Q web.mydomain.test".
27 uint8_t test_order_query_msgbuf[30] = {
28 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x65, 0x62, 0x2e, 0x6d, 0x79, 0x64,
29 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00, 0x01, 0x00, 0x01
30 };
31 #if 0
32 0000 10 c1 01 00 00 01 00 00 00 00 00 00 03 77 65 62
33 0010 08 6d 79 64 6f 6d 61 69 6e 04 74 65 73 74 00 00
34 0020 01 00 01
35
36 0000 ef 53 01 00 00 01 00 00 00 00 00 00 03 77 65 62
37 0010 08 6d 79 64 6f 6d 61 69 6e 04 74 65 73 74 00 00
38 0020 01 00 01
39
40 uint8_t test_query_client_msgbuf[35] = {
41 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x73, 0x65, 0x72, 0x76, 0x65,
42 0x72, 0x2e, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00,
43 0x01, 0x00, 0x01
44 };
45 #endif
46 // This uDNS message is a canned response that was originally captured by wireshark.
47 uint8_t test_order_response1_msgbuf[228] = {
48 0x0f, 0x98, // transaction id
49 0x85, 0x80, // flags
50 0x00, 0x01, // 1 query: web.mydomain.test: type A, class IN
51 0x00, 0x04, // 4 anwsers: Addr 10.0.0.101, Addr 10.0.0.105, Addr 10.0.0.104, Addr 10.0.0.102
52 0x00, 0x01, // 1 authoritative nameservers: mydomain.test: type NS, class IN, ns ns.mydomain.test
53 0x00, 0x01, // 1 additional: ns.mydomain.test: type A, class IN, addr 192.168.0.23
54 0x03, 0x77, 0x65, 0x62,
55 0x08, 0x6d, 0x79, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x04, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00,
56 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
57 0x00, 0x00, 0x65, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
58 0x00, 0x00, 0x69, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
59 0x00, 0x00, 0x68, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
60 0x00, 0x00, 0x66, 0xc0, 0x10, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x05, 0x02,
61 0x6e, 0x73, 0xc0, 0x10, 0xc0, 0x6f, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x04,
62 0xc0, 0xa8, 0x00, 0x17
63 };
64
65 // This uDNS message is a canned response that was originally captured by wireshark, then modified to match above (other than Addr order).
66 uint8_t test_order_response2_msgbuf[228] = {
67 0x0f, 0x98, // transaction id
68 0x85, 0x80, // flags
69 0x00, 0x01, // 1 query: web.mydomain.test: type A, class IN
70 0x00, 0x04, // 4 anwsers: Addr 10.0.0.102, Addr 10.0.0.101, Addr 10.0.0.104, Addr 10.0.0.105
71 0x00, 0x01, // 1 authoritative nameservers: mydomain.test: type NS, class IN, ns ns.mydomain.test
72 0x00, 0x01, // 1 additional: ns.mydomain.test: type A, class IN, addr 192.168.0.23
73 0x03, 0x77, 0x65, 0x62,
74 0x08, 0x6d, 0x79, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x04, 0x74, 0x65, 0x73, 0x74, 0x00, 0x00,
75 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
76 0x00, 0x00, 0x66, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
77 0x00, 0x00, 0x65, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
78 0x00, 0x00, 0x68, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x0a,
79 0x00, 0x00, 0x69, 0xc0, 0x10, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x05, 0x02,
80 0x6e, 0x73, 0xc0, 0x10, 0xc0, 0x6f, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x04,
81 0xc0, 0xa8, 0x00, 0x17
82 };
83
84 // Variables associated with contents of the above uDNS message
85 char test_order_domainname_cstr[] = "web.mydomain.test.";
86
87 @interface CacheOrderTest : XCTestCase
88 {
89 UDPSocket* local_socket;
90 request_state* client_request_message;}
91 @end
92
93 @implementation CacheOrderTest
94
95 // The InitThisUnitTest() initializes the mDNSResponder environment as well as
96 // a DNSServer. It also allocates memory for a local_socket and client request.
97 // Note: This unit test does not send packets on the wire and it does not open sockets.
98 - (void)setUp
99 {
100 mDNSPlatformMemZero(&mDNSStorage, sizeof(mDNS));
101
102 // Init unit test environment and verify no error occurred.
103 mStatus result = init_mdns_environment(mDNStrue);
104 XCTAssertEqual(result, mStatus_NoError);
105
106 // Add one DNS server and verify it was added.
107 AddDNSServer_ut();
108 XCTAssertEqual(CountOfUnicastDNSServers(&mDNSStorage), 1);
109
110 // Create memory for a socket that is never used or opened.
111 local_socket = (UDPSocket *) mDNSPlatformMemAllocateClear(sizeof(*local_socket));
112
113 // Create memory for a request that is used to make this unit test's client request.
114 client_request_message = calloc(1, sizeof(request_state));
115 }
116
117 - (void)tearDown
118 {
119 mDNS *m = &mDNSStorage;
120 request_state* req = client_request_message;
121 DNSServer *ptr, **p = &m->DNSServers;
122
123 while (req->replies)
124 {
125 reply_state *reply = req->replies;
126 req->replies = req->replies->next;
127 mDNSPlatformMemFree(reply);
128 }
129 mDNSPlatformMemFree(req);
130
131 mDNSPlatformMemFree(local_socket);
132
133 while (*p)
134 {
135 ptr = *p;
136 *p = (*p)->next;
137 LogInfo("FinalizeUnitTest: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
138 mDNSPlatformMemFree(ptr);
139 }
140 }
141
142 - (void)testSuspiciousReplyTestSeries
143 {
144 [self _clientQueryRequest];
145 [self _verifyCacheOrderBehavior];
146 }
147
148 // Simulate a uds client request by setting up a client request and then
149 // calling mDNSResponder's handle_client_request. The handle_client_request function
150 // processes the request and starts a query. This unit test verifies
151 // the client request and query were setup as expected. This unit test also calls
152 // mDNS_execute which determines the cache does not contain the new question's
153 // answer.
154 - (void)_clientQueryRequest
155 {
156 mDNS *const m = &mDNSStorage;
157 request_state* req = client_request_message;
158 char *msgptr = (char *)test_order_query_msgbuf;
159 size_t msgsz = sizeof(test_order_query_msgbuf);
160 mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
161 DNSQuestion *q;
162 mStatus err = mStatus_NoError;
163 char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
164
165 // Process the unit test's client request
166 start_client_request(req, msgptr, msgsz, query_request, local_socket);
167 XCTAssertEqual(err, mStatus_NoError);
168
169 // Verify the request fields were set as expected
170 XCTAssertNil((__bridge id)req->next);
171 XCTAssertNil((__bridge id)req->primary);
172 XCTAssertEqual(req->sd, client_req_sd);
173 XCTAssertEqual(req->process_id, client_req_process_id);
174 XCTAssertFalse(strcmp(req->pid_name, client_req_pid_name));
175 XCTAssertEqual(req->validUUID, mDNSfalse);
176 XCTAssertEqual(req->errsd, 0);
177 XCTAssertEqual(req->uid, client_req_uid);
178 XCTAssertEqual(req->ts, t_complete);
179 XCTAssertGreaterThan((mDNSs32)req->data_bytes, min_size);
180 XCTAssertEqual(req->msgend, msgptr+msgsz);
181 XCTAssertNil((__bridge id)(void*)req->msgbuf);
182 XCTAssertEqual(req->hdr.version, VERSION);
183 XCTAssertNil((__bridge id)req->replies);
184 XCTAssertNotEqual(req->terminate, (req_termination_fn)0);
185 XCTAssertEqual(req->flags, kDNSServiceFlagsReturnIntermediates);
186 XCTAssertEqual(req->interfaceIndex, kDNSServiceInterfaceIndexAny);
187
188 // Verify the query fields were set as expected
189 q = &req->u.queryrecord.op.q;
190 XCTAssertNotEqual(q, (DNSQuestion *)mDNSNULL);
191 XCTAssertEqual(q, m->Questions);
192 XCTAssertEqual(q, m->NewQuestions);
193 XCTAssertEqual(q->SuppressUnusable, mDNSfalse);
194 XCTAssertEqual(q->ReturnIntermed, mDNStrue);
195 XCTAssertEqual(q->Suppressed, mDNSfalse);
196
197 ConvertDomainNameToCString(&q->qname, qname_cstr);
198 XCTAssertFalse(strcmp(qname_cstr, test_order_domainname_cstr));
199 XCTAssertEqual(q->qnamehash, DomainNameHashValue(&q->qname));
200
201 XCTAssertEqual(q->InterfaceID, mDNSInterface_Any);
202 XCTAssertEqual(q->flags, req->flags);
203 XCTAssertEqual(q->qtype, 1);
204 XCTAssertEqual(q->qclass, 1);
205 XCTAssertEqual(q->LongLived, 0);
206 XCTAssertEqual(q->ExpectUnique, mDNSfalse);
207 XCTAssertEqual(q->ForceMCast, 0);
208 XCTAssertEqual(q->TimeoutQuestion, 0);
209 XCTAssertEqual(q->WakeOnResolve, 0);
210 XCTAssertEqual(q->UseBackgroundTraffic, 0);
211 XCTAssertEqual(q->ProxyQuestion, 0);
212 XCTAssertNotEqual((void*)q->QuestionCallback, (void*)mDNSNULL);
213 XCTAssertEqual(q->AppendSearchDomains, 0);
214 XCTAssertNil((__bridge id)q->DuplicateOf);
215
216 // Call mDNS_Execute to see if the new question, q, has an answer in the cache.
217 // It won't be yet because the cache is empty.
218 m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
219 mDNS_Execute(m);
220
221 // Verify mDNS_Execute processed the new question.
222 XCTAssertNil((__bridge id)m->NewQuestions);
223
224 // Verify the cache is empty and the request got no reply.
225 XCTAssertEqual(m->rrcache_totalused, 0);
226 XCTAssertNil((__bridge id)req->replies);
227 }
228
229 // This unit test performs two queries and verifies the cache oredr is updated on a new response.
230 // 1) Verify response is ordered in the cache as expected
231 // 2) Test again with new response, and verify cache order is updated
232 - (void)_verifyCacheOrderBehavior
233 {
234 mDNS *const m = &mDNSStorage;
235 DNSMessage *msgptr;
236 size_t msgsz;
237 request_state* req = client_request_message;
238 DNSQuestion *q = &req->u.queryrecord.op.q;
239 mStatus status;
240
241 // 1)
242 // Process first response
243 // Verify response cache count & order
244
245 msgptr = (DNSMessage *)test_order_response1_msgbuf;
246 msgsz = sizeof(test_order_response1_msgbuf);
247 receive_response(req, msgptr, msgsz);
248
249 // Verify records received
250 mDNSu32 CacheUsed =0, notUsed =0;
251 LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, &notUsed);
252 XCTAssertEqual(CacheUsed, 5); // Verify 4 records received + Cache Group
253
254 // Verify record order
255 mDNSu8 lastoctet1[4] = {101, 105, 104, 102};
256 status = verify_cache_addr_order_for_domain_ut(m, lastoctet1, 4, &q->qname);
257 XCTAssertEqual(status, mStatus_NoError, @"Cache order test 1 failed");
258
259 // 2)
260 // Process second response
261 // Verify response cache count & order
262
263 msgptr = (DNSMessage *)test_order_response2_msgbuf;
264 msgsz = sizeof(test_order_response2_msgbuf);
265 receive_response(req, msgptr, msgsz);
266
267 // Verify records received
268 LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, &notUsed);
269 XCTAssertEqual(CacheUsed, 5); // Verify 4 records received + Cache Group
270
271 // Verify record order
272 mDNSu8 lastoctet2[4] = {102, 101, 104, 105};
273 status = verify_cache_addr_order_for_domain_ut(m, lastoctet2, 4, &q->qname);
274 XCTAssertEqual(status, mStatus_NoError, @"Cache order test 2 failed");
275 }
276
277
278 @end